package task

import (
	"context"
	"time"

	"probe-scheduler/internal/metrics"
	probePb "probe-scheduler/pb/probe"
	pb "probe-scheduler/pb/scheduler"

	"github.com/zeromicro/go-zero/core/logx"
)

// Executor 任务执行器，负责调用外部探测服务
type Executor struct {
	probeClient probePb.ProbeServiceClient
	Metrics     *metrics.ProbeMetrics
}

// NewExecutor 创建执行器实例
func NewExecutor(probeClient probePb.ProbeServiceClient, resultChan chan *pb.TaskResult) *Executor {
	return &Executor{
		probeClient: probeClient,
		Metrics:     metrics.NewProbeMetrics(),
	}
}

// Execute 执行任务，调用对应的探测服务
func (e *Executor) Execute(ctx context.Context, task *pb.Task) {
	startTime := time.Now()
	result := &pb.TaskResult{
		TaskId:   task.Id,
		ExecTime: startTime.UnixMilli(),
		Success:  false,
	}

	logx.Infof("Starting execution of task %d with probe type %v", task.Id, task.ProbeConfig.Type)

	// 根据探测类型调用相应的探测服务
	switch task.ProbeConfig.Type {
	case pb.ProbeType_HTTP:
		e.handleHttpProbe(ctx, task, result)
		e.Metrics.UpdateHttpMetrics(task.ProbeConfig.Target, float64(result.HttpStatus), result.Duration)
	case pb.ProbeType_TCP:
		e.handleTcpProbe(ctx, task, result)
		e.Metrics.UpdateTcpMetrics(task.ProbeConfig.Target, result.Success, result.Duration)
	case pb.ProbeType_DNS:
		e.handleDnsProbe(ctx, task, result)
		e.Metrics.UpdateDnsMetrics(task.ProbeConfig.Target, result.Success, result.Duration)
	default:
		result.Error = "unsupported probe type"
		logx.Errorf("Unsupported probe type: %v for task %d", task.ProbeConfig.Type, task.Id)
	}
}

// 处理HTTP探测
func (e *Executor) handleHttpProbe(ctx context.Context, task *pb.Task, result *pb.TaskResult) {
	timeout := task.ProbeConfig.Timeout
	if timeout <= 0 {
		timeout = 5 // 默认5秒
	}

	logx.Infof("Handling HTTP probe for task %d with target %s and timeout %d seconds", task.Id, task.ProbeConfig.Target, timeout)

	// 创建带超时的上下文
	ctxWithTimeout, cancel := context.WithTimeout(ctx, time.Duration(timeout)*time.Second)
	defer cancel()

	// 调用外部HTTP探测服务
	req := &probePb.HttpProbeRequest{
		Url:     task.ProbeConfig.Target,
		Timeout: int32(timeout),
	}

	logx.Infof("Sending HttpProbe request: %+v", req)

	// 添加调试日志，查看连接状态
	logx.Infof("About to call HttpProbe with context deadline: %v", ctxWithTimeout.Err())

	resp, err := e.probeClient.HttpProbe(ctxWithTimeout, req)

	if err != nil {
		result.Error = err.Error()
		logx.Errorf("HttpProbe failed for task %d: %v", task.Id, err)
		// 添加更多错误详情
		if ctxWithTimeout.Err() != nil {
			logx.Errorf("Context error: %v", ctxWithTimeout.Err())
		}
		return
	}

	result.Success = resp.Success
	result.Error = resp.Error
	result.HttpStatus = resp.Status
	result.Duration = resp.Duration
	// 添加探测类型
	result.Type = resp.Type

	logx.Infof("HttpProbe succeeded for task %d with status %d", task.Id, resp.Status)
}

// 处理TCP探测
func (e *Executor) handleTcpProbe(ctx context.Context, task *pb.Task, result *pb.TaskResult) {
	timeout := task.ProbeConfig.Timeout
	if timeout <= 0 {
		timeout = 5 // 默认5秒
	}

	logx.Infof("Handling TCP probe for task %d with target %s and timeout %d seconds", task.Id, task.ProbeConfig.Target, timeout)

	// 创建带超时的上下文
	ctxWithTimeout, cancel := context.WithTimeout(ctx, time.Duration(timeout)*time.Second)
	defer cancel()

	// 调用外部TCP探测服务
	req := &probePb.TcpProbeRequest{
		Address: task.ProbeConfig.Target,
		Timeout: int32(timeout),
	}

	logx.Infof("Sending TcpProbe request: %+v", req)

	resp, err := e.probeClient.TcpProbe(ctxWithTimeout, req)

	if err != nil {
		result.Error = err.Error()
		logx.Errorf("TcpProbe failed for task %d: %v", task.Id, err)
		return
	}

	result.Success = resp.Success
	result.Error = resp.Error
	result.Duration = resp.Duration
	result.Type = resp.Type

	logx.Infof("TcpProbe succeeded for task %d", task.Id)
}

// 处理DNS探测
func (e *Executor) handleDnsProbe(ctx context.Context, task *pb.Task, result *pb.TaskResult) {
	timeout := task.ProbeConfig.Timeout
	if timeout <= 0 {
		timeout = 5 // 默认5秒
	}

	logx.Infof("Handling DNS probe for task %d with target %s and timeout %d seconds", task.Id, task.ProbeConfig.Target, timeout)

	// 创建带超时的上下文
	ctxWithTimeout, cancel := context.WithTimeout(ctx, time.Duration(timeout)*time.Second)
	defer cancel()

	// 调用外部DNS探测服务
	req := &probePb.DnsProbeRequest{
		Domain:  task.ProbeConfig.Target,
		Timeout: int32(timeout),
	}

	logx.Infof("Sending DnsProbe request: %+v", req)

	resp, err := e.probeClient.DnsProbe(ctxWithTimeout, req)

	if err != nil {
		result.Error = err.Error()
		logx.Errorf("DnsProbe failed for task %d: %v", task.Id, err)
		return
	}

	result.Success = resp.Success
	result.Error = resp.Error
	result.DnsIps = resp.Ips
	result.Duration = resp.Duration
	result.Type = resp.Type

	logx.Infof("DnsProbe succeeded for task %d with IPs: %v", task.Id, resp.Ips)
}
